/**
 * @name 树形结构数据处理
 */
// 默认配置信息，由于数据中存在的id、pid等属性可能存在其他的映射关系
const defaults = {
  idKey: 'id', // 唯一id的key
  pidKey: 'pid', // 父节点id的key
  childrenKey: 'children', // 子元素集合的key
  rootId: 0, // 根节点的id
};

/**
 * @param {array} list 扁平树形数据,变树形结构的源数据
 * @param {object} options
 */
const Tree = function Tree(list, options) {
  this.options = { ...defaults, ...options };
  this.list = list || [];
  this.treeList = [];
};

/**
 * @name 扁平树形数据转树形数组
 * @param {array} targetList 扁平树形数据
 * @param {object} options 配置信息
 * @returns array
 */
const getTreeListFromList = function getTreeListFromList(targetList, options) {
  const tree = new Tree(targetList, options);
  const treeList = tree.toTreeList().getTreeList();
  return treeList;
};

/**
 * @name 扁平树形数据转树形数组
 * @returns object 当前实例化
 */
Tree.prototype.toTreeList = function toTreeList() {
  const { idKey, pidKey, childrenKey, rootId } = this.options;
  const map = {};
  for (const item of this.list) {
    const { [idKey]: id, [pidKey]: pid } = item;
    if (!map[id]) {
      map[id] = {
        [childrenKey]: [],
      };
    }
    map[id] = {
      ...item,
      [childrenKey]: map[id][childrenKey],
    };
    const treeItem = map[id];
    if (id === rootId) {
      this.treeList = [treeItem];
    } else {
      if (!map[pid]) {
        map[pid] = {
          [childrenKey]: [],
        };
      } else {
        map[pid][childrenKey].push(treeItem);
      }
    }
  }
  return this;
};
/**
 * @name 获取树形数组
 * @returns array
 */
Tree.prototype.getTreeList = function getTreeList() {
  return this.treeList || [];
};
/**
 * @name 获取扁平树形数组
 * @returns array
 */
Tree.prototype.getList = function getList() {
  return this.list || [];
};

/**
 * @name 在树形数组中根据指定id获取节点对象
 * @param {*} targetId 目标ID
 * @returns array
 */
Tree.prototype.getNodeFromTreeListById = function getNodeFromTreeListById(targetId) {
  let ret = null;
  if (targetId === null || targetId === undefined) return ret;
  const { idKey, childrenKey } = this.options;
  const wrapper = function wrapper(treeList, id) {
    for (const item of treeList) {
      const { [idKey]: itemId, [childrenKey]: itemChildren } = item;
      if (id === itemId) {
        ret = item;
        break;
      } else {
        wrapper(itemChildren || [], id);
      }
    }
  };
  wrapper(this.treeList, targetId);
  return ret;
};
/**
 * @name 在树形数组中根据指定id获取路径节点集合
 * @param {*} targetId 目标ID
 * @returns array
 */
Tree.prototype.getPathNodesFromTreeListById = function getPathNodesFromTreeListById(targetId) {
  const ret = [];
  if (targetId === null || targetId === undefined) return ret;
  const { idKey, pidKey, childrenKey, rootId } = this.options;
  const targetTreeList = this.treeList;
  const wrapper = function wrapper(treeList, id) {
    for (const item of treeList) {
      const { [idKey]: itemId, [pidKey]: itemPid, [childrenKey]: itemChildren } = item;
      if (id === itemId) {
        ret.unshift(item);
        if (targetId !== rootId) {
          wrapper(targetTreeList, itemPid);
        }
        break;
      } else {
        wrapper(itemChildren || [], id);
      }
    }
  };
  wrapper(targetTreeList, targetId);
  return ret;
};

/**
 * @name 在扁平树形数组中根据指定id获取路径节点集合
 * @param {*} targetId 目标ID
 * @returns array
 */
Tree.prototype.getPathNodesFromListById = function getPathNodesFromListById(targetId) {
  const ret = [];
  if (targetId === null || targetId === undefined) return ret;
  const { idKey, pidKey, rootId } = this.options;
  const wrapper = function wrapper(list, id) {
    let pid;
    for (const item of list) {
      const { [idKey]: itemId, [pidKey]: itemPid } = item;
      if (itemId === id) {
        ret.unshift(item);
        pid = itemPid;
        break;
      }
    }
    if (id !== rootId && pid !== null && pid !== undefined) {
      wrapper(list, pid);
    }
  };
  wrapper(this.list, targetId);
  return ret;
};

Tree.getTreeListFromList = getTreeListFromList;
export { getTreeListFromList };
export default Tree;
